#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author: LiangChao
@email：kevinleong1011@hotmail.com
@desc: 
"""
import inspect
import os
import re

from makit.py import find_project_root

from makitest.errors import InvalidTestError


def get_test_name(obj):
    """
    获取被测对象名称
    :param obj:
    :return:
    """
    if inspect.isfunction(obj):
        name = re.search(r'<function (\S+) at', str(obj)).groups()[0]
        return f'{inspect.getmodule(obj).__name__}.{name}'
    elif inspect.ismethod(obj):
        name = re.search(r'<bound method (\S+) of', str(obj)).groups()[0]
        return f'{inspect.getmodule(obj).__name__}.{name}'
    elif inspect.ismodule(obj):
        return obj.__name__
    elif inspect.isclass(obj):
        return obj.__class__.__name__
    else:
        return str(obj)


def get_module_name(module, filename=None):
    name = module.__name__
    if name == '__main__':
        if not filename:
            p = re.compile(r"'(.+)' from '(.+)'")
            matches = p.findall(str(module).replace(r'\\', '/'))
            _, filename = matches[0]
        root = find_project_root(filename)
        rel_path = os.path.relpath(filename, root)
        name = re.sub(r'[\\/]+', '.', rel_path)[:-3].replace('.__init__', '')
    return name


def parse_test_info(target):
    if inspect.ismodule(target):
        return parse_module_info(target)
    elif inspect.isclass(target):
        return parse_class_info(target)
    elif inspect.isfunction(target) or inspect.isfunction(target):
        return parse_func_info(target)
    else:
        raise InvalidTestError(target)


def parse_module_info(module, filename=None):
    name = get_module_name(module, filename)
    fullname = name
    desc = getattr(module, 'desc', None)
    return name, fullname, desc


def parse_class_info(cls, module_name=None):
    name = cls.__name__
    if not module_name:
        module_name = inspect.getmodule(cls).__name__
        if module_name == '__main__':
            module_name = get_module_name(inspect.getmodule(cls))
    fullname = f'{module_name}.{name}'
    return name, fullname, cls.__doc__


def parse_func_info(func, module_name=None):
    p = re.compile(r'(?:<function|<bound method) (\S+) (?:at|of)')
    matches = p.findall(str(func))
    assert matches
    name = matches[0]
    fullname = f'{module_name or get_module_name(inspect.getmodule(func))}.{name}'
    doc = func.__doc__ or ''
    return name, fullname, doc
